#define OPENGLINTERFACE
#include "OpenglInterface.h"

namespace ModularEngine
{

	void OpenglInterface::init()
	{

	}

	void OpenglInterface::setTexture( unsigned int iTextureID )
	{
		glBindTexture( GL_TEXTURE_2D, iTextureID );
	}

	void OpenglInterface::bindTexture(unsigned int nTex)
	{
		glBindTexture( GL_TEXTURE_2D, nTex );
	}

	TextureID *OpenglInterface::loadTexture( const char *pTexturePath, const char *pMacro )
	{
		// Iterate through the texture list. 
		// If the texturename given matches either an existing path or macro name
		// return the image id.
		// If, for some reason, the macroname given matches an existing macro name then throw error.
		// Reason for this is that if it hits this if statement, then the paths don't match.
		// Can't have 1 macro point to 2 paths.
		for( std::list<TextureID>::iterator i = mlTextures.begin(); i != mlTextures.end(); i++ )
		{
			if( !strcmp( pTexturePath, i->fileName() ) )
			{
				return &(*i);
			}

			// Previously I forgot to check if macroName existed because if it doesn't exist
			// it's set automatically to NULL
			if( i->macroName() )
			{
				if( !strcmp( pTexturePath, i->macroName() ) )
					return &(*i);
			}

			if( pMacro && i->macroName() )
			{
				if( !strcmp( pMacro, i->macroName() ) )
				{
					THROWERROR( "Macro Name Already Exists." );
					return new TextureID();
				}
			}
		}

		// Load the texture using the ImageLoader class
		ModularEngine::Texture textureData = ModularEngine::ImageLoader::getSingleton().LoadTexture( pTexturePath );

		// Image loader returns a class w/ zeros if there's an error.  Check for this.
		if( textureData.mData == 0 )
		{
			//THROWERROR( "Error loading texture" );
			return new TextureID();
		}

		// Determines whether or not there's an alpha channel.
		unsigned int type = GL_RGBA;
		if( textureData.mBpp == 3 )
			type=GL_RGB;

		// Set File Name
		TextureID *nTexture = new TextureID();
		nTexture->fileName( pTexturePath );
		nTexture->mWidth = textureData.mWidth;
		nTexture->mHeight = textureData.mHeight;

		// If there is no macro name, no use setting it.
		if( pMacro )
			nTexture->macroName( pMacro );		

		
		// Enable textures
		glEnable( GL_TEXTURE_2D );
	
		// Create an unused texture id for opengl
		glGenTextures( 1, &nTexture->mTexNum );
		
		// Bind newly created texture to GL_TEXTURE_2D
		glBindTexture( GL_TEXTURE_2D, nTexture->mTexNum );
		
		// Set appropriate txture filters
		// BIG TODO: FIX ME
		// Crashes when MIN_FILTER uncommented.
		glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
		glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
		
		glTexImage2D( GL_TEXTURE_2D, 0, type, textureData.mWidth, textureData.mHeight, 0, type, GL_UNSIGNED_BYTE, textureData.mData );

		mlTextures.push_back( *nTexture );

		delete [] textureData.mData;
		textureData.mData = 0;
		
		return nTexture;	
	}

	void OpenglInterface::drawImage( const char *pTexturePath, Vector2d vPos )
	{
		TextureID *tex = loadTexture( pTexturePath );
		glEnable( GL_TEXTURE_2D );
		glBindTexture( GL_TEXTURE_2D, tex->mTexNum );
		glBegin( GL_QUADS );
			glTexCoord2f( 0, 1 );
			glVertex2f( vPos.x, vPos.y );
			glTexCoord2f( 1, 1 );
			glVertex2f( vPos.x+tex->mWidth, vPos.y );
			glTexCoord2f( 1, 0 );
			glVertex2f( vPos.x+tex->mWidth, vPos.y+tex->mHeight );
			glTexCoord2f( 0, 0 );
			glVertex2f( vPos.x, vPos.y+tex->mHeight );
		glEnd();
	}

	void OpenglInterface::drawQuad(ModularEngine::Vector2d vPos, ModularEngine::Vector2d vDims)
	{
		glBegin( GL_QUADS );
			glVertex3f( vPos.x, vPos.y, 0 );
			glVertex3f( vPos.x+vDims.x, vPos.y, 0 );
			glVertex3f( vPos.x+vDims.x, vPos.y+vDims.y, 0 );
			glVertex3f( vPos.x, vPos.y+vDims.y, 0 );
		glEnd();
	}

	void OpenglInterface::drawQuad(unsigned int nTexture, ModularEngine::Vector2d vPos, ModularEngine::Vector2d vDims)
	{
		glEnable( GL_TEXTURE_2D );
		glBindTexture( GL_TEXTURE_2D, nTexture );
		glBegin( GL_QUADS );
			glTexCoord2f( 0, 1 );
			glVertex2f( vPos.x, vPos.y );
			glTexCoord2f( 1, 1 );
			glVertex2f( vPos.x+vDims.x, vPos.y );
			glTexCoord2f( 1, 0 );
			glVertex2f( vPos.x+vDims.x, vPos.y+vDims.y );
			glTexCoord2f( 0, 0 );
			glVertex2f( vPos.x, vPos.y+vDims.y );
		glEnd();

	}

	void OpenglInterface::drawQuad(unsigned int nTexture, ModularEngine::Vector2d vTexCoords[], ModularEngine::Vector2d vPos, ModularEngine::Vector2d vDims)
	{

		glEnable( GL_TEXTURE_2D );
		glBindTexture( GL_TEXTURE_2D, nTexture );
		glBegin( GL_QUADS );
			glTexCoord2f( vTexCoords[0].x, vTexCoords[1].y);
			glVertex2f( vPos.x, vPos.y );
			glTexCoord2f( vTexCoords[1].x, vTexCoords[1].y);
			glVertex2f( vPos.x+vDims.x, vPos.y );
			glTexCoord2f( vTexCoords[1].x, vTexCoords[0].y );
			glVertex2f( vPos.x+vDims.x, vPos.y+vDims.y );
			glTexCoord2f( vTexCoords[0].x, vTexCoords[0].y );
			glVertex2f( vPos.x, vPos.y+vDims.y );
		glEnd();

	}

	void OpenglInterface::startDrawing( unsigned int iState )
	{
		glBegin( translateMessages( iState ) );
	}

	void OpenglInterface::stopDrawing()
	{
		glEnd();
	}

	void OpenglInterface::enable(unsigned int iState)
	{
		glEnable( translateMessages( iState ) );
	}

	void OpenglInterface::disable(unsigned int iState)
	{
		glDisable( translateMessages( iState ) );
	}

	unsigned int OpenglInterface::translateMessages(unsigned int giMessage)
	{
		if( giMessage >= GI_LINES && giMessage <= GI_POLYGON )
		{
			return giMessage - GI_LINES;
		}

		switch( giMessage )
		{
		case GI_TEXTURE:
			return GL_TEXTURE_2D;
		case GI_DEPTH_BUFFER_BIT:
			return GL_DEPTH_BUFFER_BIT;
		case GI_COLOR_BUFFER_BIT:
			return GL_COLOR_BUFFER_BIT;
		}

		return -1;
	}
}